package com.lagou.edu.spring.core.impl;

import com.lagou.edu.spring.core.ApplicationContext;
import com.lagou.edu.spring.core.BeanDefinition;
import com.lagou.edu.spring.core.BeanDefinitionRegistry;
import com.lagou.edu.spring.core.BeanFactory;
import com.lagou.edu.spring.core.BeanFactoryPostProcessor;
import com.lagou.edu.spring.core.BeanPostProcessor;
import com.lagou.edu.spring.core.defaults.DefaultBeanDefinitionRegistry;
import com.lagou.edu.spring.core.defaults.DefaultBeanFactory;
import com.lagou.edu.spring.core.processors.AutowiredParserProcessor;
import com.lagou.edu.spring.core.processors.BeanParserProcessor;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 大犬
 * @date 2020/3/31
 */
public abstract class AbstractApplicationContext implements ApplicationContext {


    private BeanFactory beanFactory;
    private BeanDefinitionRegistry beanDefinitionRegistry;

    public AbstractApplicationContext() {
        beanFactory = new DefaultBeanFactory();
        beanDefinitionRegistry = new DefaultBeanDefinitionRegistry();
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionRegistry.register(beanName, beanDefinition);
    }

    @Override
    public void refresh() {
        // 1.准备工作
        prepareRefresh();
        // 2.执行所有工厂处理器，这一步中主要是对bean的定义信息做进一步的处理
        // 比如Autowired注解解析器，Bean注解解析器的创建和调用
        invokeBeanFactoryProcessors();
        // 3.创建所有bean处理器，创建容器中所有bean处理器
        createBeanProcessors();
        // 4.完成创建所有的bean，包括创建bean实例，属性设置，初始化，bean处理器调用等等
        // 这一步会进行事务处理器的调用，从而增强bean的事务方法
        createAllBeans();
        // 5.完成容器的refresh操作
        finishRefresh();
    }

    private void invokeBeanFactoryProcessors() {
        Set<BeanFactoryPostProcessor> allProcessors = new HashSet<>();
        // 因为bean工厂处理器执行时可能会生成新的BeanFactoryPostProcessor对象，所以需要循环处理，
        // 直到把所有的BeanFactoryPostProcessor处理完毕，并不再有新的BeanFactoryPostProcessor对象产生为止
        while (true) {
            List<BeanFactoryPostProcessor> postProcessors = beanFactory.getBeans(BeanFactoryPostProcessor.class);
            boolean hasNew = false;
            for (BeanFactoryPostProcessor postProcessor : postProcessors) {
                if (allProcessors.contains(postProcessor)) {
                    continue;
                }
                hasNew = true;
                // 执行工厂处理器前置处理方法，该方法执行后，有可能会生成新的beanDefinition对象
                postProcessor.preProcessBeanFactory(beanDefinitionRegistry, this);
                allProcessors.add(postProcessor);
            }
            if (!hasNew) {
                break;
            }
        }
        // bean工厂处理器调用完成之后，需要将beanDefinitionRegistry冻结住，
        // 保证在之后创建和处理一般bean的过程中不会有新的bean生成从而无法完成容器初始化
        beanDefinitionRegistry.freeze();
        // 执行后置处理
        allProcessors.forEach(processor -> processor.afterProcessBeanFactory(beanDefinitionRegistry, this));

    }

    private void prepareRefresh() {
        // 1.获取bean工厂,把bean的所有定义信息都交给beanFactory
        ((DefaultBeanFactory) beanFactory).importBeanDefinitionRegistry(beanDefinitionRegistry);
        // 2.添加bean注解处理器
        addComponent(BeanParserProcessor.class);
        // 3.添加Autowired注解处理器
        addComponent(AutowiredParserProcessor.class);
    }

    private void addComponent(Class componentClass) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanName(componentClass.getSimpleName());
        beanDefinition.setBeanType(componentClass);
        registerBeanDefinition(beanDefinition.getBeanName(), beanDefinition);
    }

    private void finishRefresh() {
        // 告知工厂，创建已经完成
        ((DefaultBeanFactory) beanFactory).finish();
    }

    private void createAllBeans() {
        // 首先获取到所有的beanName
        List<String> allBeanNames = beanDefinitionRegistry.getAllBeanNames();
        // 根据beanName创建所有的bean
        allBeanNames.forEach(beanFactory::getBean);
    }

    private void createBeanProcessors() {
        // 获取所有的BeanPostProcessor的beanName
        List<String> beanNames = beanDefinitionRegistry.getBeanNames(BeanPostProcessor.class);
        // 根据beanName创建所有的BeanPostProcessor的bean对象
        beanNames.forEach(beanFactory::getBean);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> beanType) {

        return beanFactory.getBean(beanName, beanType);
    }

    @Override
    public <T> List<T> getBeans(Class<T> beanType) {
        return beanFactory.getBeans(beanType);
    }

    @Override
    public Object getBean(String beanName) {
        return beanFactory.getBean(beanName);
    }

    @Override
    public <T> T getBean(Class<T> beanType) {
        return beanFactory.getBean(beanType);
    }

    @Override
    public void close() {
        ((DefaultBeanFactory) beanFactory).clear();
    }
}
